﻿/// <reference path="jquery.js" />
/// <reference path="Liber.Base.js" />
'use strict'

if (!window.LiberUI) {
    window.GetDPI = function () {
        var arrDPI = new Array;
        if (!window.screen.deviceYDPI) {
            var tmpNode = document.createElement("DIV");
            tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
            document.body.appendChild(tmpNode);
            arrDPI[0] = parseInt(tmpNode.offsetWidth);
            arrDPI[1] = parseInt(tmpNode.offsetHeight);
            tmpNode.parentNode.removeChild(tmpNode);
        }
        else {
            arrDPI[0] = window.screen.deviceXDPI;
            arrDPI[1] = window.screen.deviceYDPI;
        }
        return arrDPI;
    };
    window.LiberUI = {};
    var MouseEvent = null;
    var mouseStoper = null;
    LiberUI.IsCheckingMouse = false;
    LiberUI.MouseMoinitor = function (ev) {
        /*捕获鼠标事件待后面使用*/
        MouseEvent = ev || window.event;
        ev && ev.stopPropagation();
    };
    LiberUI.Stopper = function () {
        //MouseEvent = null;
        LiberUI.IsCheckingMouse = false;
        document.removeEventListener("mousemove", LiberUI.MouseMoinitor);
        document.removeEventListener("click", LiberUI.MouseMoinitor);
        window.clearTimeout(mouseStoper);
    };
    LiberUI.TryGetHotElement = function () {
        if (LiberUI.IsCheckingMouse == false) {
            document.addEventListener("mousemove", LiberUI.MouseMoinitor);
            document.addEventListener("click", LiberUI.MouseMoinitor);
            LiberUI.IsCheckingMouse = true;

            //停止将要执行的停止动作
            if (mouseStoper != null) {
                window.clearTimeout(mouseStoper);
            }
            mouseStoper = setTimeout(LiberUI.Stopper, 5000);  //5秒后停止监听,除非此方法被再次调用
            return MouseEvent == null ? null : $(MouseEvent.toElement);
        }
        else {
            //TODO:计算鼠标当前停留的元素,考虑不同浏览器的实现方式
            //停止将要执行的停止动作
            if (mouseStoper != null) {
                window.clearTimeout(mouseStoper);
            }
            mouseStoper = setTimeout(LiberUI.Stopper, 5000);  //5秒后停止监听,除非此方法被再次调用
            return MouseEvent == null ? null : $(MouseEvent.toElement);
        }
    };

    //初始化快速UI支持
    $(function () {
        var tpm = $('<div id="tplPrompt" cntid="prompt" style="display:none"><div class="prompt_success"><div class="p_body"><h4>title</h4><span>message</span></div></div><div class="prompt_info"><div class="p_body"><h4>title</h4><span>message</span></div></div><div class="prompt_err"><div class="p_body"><h4>title</h4><span>message</span></div></div><div class="prompt_warn"><div class="p_body"><h4>title</h4><span>message</span></div></div></div>').appendTo("body");

        window.success = function (title, msg, delay, fnCallback) {
            var cnt = $("#tplPrompt>.prompt_success").clone();
            cnt.children(".p_body").children("h4").vl(title);
            cnt.children(".p_body").children("span").vl(msg);
            var p = new LiberUI.Prompt(cnt);
            p.option("Delay", delay);
            p.update();
            if (ObjHelper.IsFunc(fnCallback)) {
                p.on("disposed", fnCallback);
            }
            return p.show();

        };
        window.info = function (title, msg, delay, fnCallback) {
            var cnt = $("#tplPrompt>.prompt_info").clone();
            cnt.children(".p_body").children("h4").vl(title);
            cnt.children(".p_body").children("span").vl(msg);
            var p = new LiberUI.Prompt(cnt);
            p.option("Delay", delay);
            p.update();
            if (ObjHelper.IsFunc(fnCallback)) {
                p.on("disposed", fnCallback);
            }
            return p.show();
        };
        window.warn = function (title, msg, delay, fnCallback) {
            var cnt = $("#tplPrompt>.prompt_warn").clone();
            cnt.children(".p_body").children("h4").vl(title);
            cnt.children(".p_body").children("span").vl(msg);
            var p = new LiberUI.Prompt(cnt);
            p.option("Delay", delay);
            p.update();
            if (ObjHelper.IsFunc(fnCallback)) {
                p.on("disposed", fnCallback);
            }
            return p.show();
        };
        window.err = function (title, msg, delay, fnCallback) {
            var cnt = $("#tplPrompt>.prompt_err").clone();
            cnt.children(".p_body").children("h4").vl(title);
            cnt.children(".p_body").children("span").vl(msg);
            var p = new LiberUI.Prompt(cnt);
            p.option("Delay", delay);
            p.update();
            if (ObjHelper.IsFunc(fnCallback)) {
                p.on("disposed", fnCallback);
            }
            return p.show();
        };

        //鼠标跟随提示
        var tipFor = new LiberUI.ToolsTip();
        $("body").delegate("[tip]", "mouseenter", function (ev) {
            //tip.text($(this).attr("tip"));
            tipFor.TipFor($(this))
                .Cnt($(this).attr("tip"))
                .Update(ev);
        }).delegate("[tip]", "mouseleave", tipFor.Hide)
          .delegate("[tip]", "mousemove", tipFor.Update);
    });

    LiberUI.Confirm = function (ttl, cnt, fnNext, waiting, fnCancel, nextBtnName, cancelBtnName) {
        /// <summary>
        /// 进行下一步操作前通知用户
        /// </summary>
        /// <param name="ttl" type="String">标题</param>
        /// <param name="cnt" type="Dom or String">通知内容，可以为一个DOM元素或字符串</param>
        /// <param name="fnNext" type="Function">如果用户确认或时间到达时执行的下一步操作</param>
        /// <param name="waiting" type="Numbric">如果>0则在等待N秒后自动放弃</param>
        /// <param name="fnCancel" type="Fnction">如果允许用户取消，则在取消时回调</param>

        var dlg = new LiberUI.Dialoger().option('Width',260);
        dlg.Title(ttl || '请确认')
            .Content(cnt);

        dlg.BtnEnter(nextBtnName || "确认", "", fnNext || function () { fnCancel == null; dlg.dispose(); }, "onrisky");

        if (fnCancel) {
            dlg.option("Closeble", true);
            dlg.BtnEsc(cancelBtnName || "取消", "", function () { dlg.dispose(); fnCancel && fnCancel(); });
        }
        else {
            dlg.option("Closeble", false);
        };

        if (!isNaN(parseInt(waiting)) && waiting > 0) {
            setTimeout(function (fn) {
                var r = dlg.dispose();
                if (r != null) {
                    fn && fn.call(dlg);
                }
            }, waiting * 1000, fnCancel);
        }
        dlg.update();
        dlg.show();
        return dlg;
    };
}

function LController($elm) {
    if (ObjHelper.IsEmpty($elm)) {
        $elm = $("<div>");
    }
    else {
        $elm = $($elm);
        if ($elm.length > 0) {
            $elm = $elm.eq(0);
        }
        else {
            $elm = $("<div>");
        }
    }
    var ins = this;
    //var evHandls = {};
    var opt = { StyleDisable: "disabled" };
    opt.ShowWay = function (elm) {
        elm.show();
    };
    opt.HideWay = function (elm) {
        elm.hide();
    };

    var data = null;
    this.State = {
        disposed: false,
        enabled: true,
        visible: false,
    };
    this.Dom = $elm;

    this.on = function (event, fn) {
        if (event == "focus" || event == "click" || event == "dbclick" || event == "blur") {
            event = "LC" + event;
        }
        this.Dom.on(event, fn);
        return this;
    };

    this.off = function (event, fn) {
        this.Dom.off(event, fn);
        return this;
    };

    this.vl = function (value) {
        if (value === undefined) {
            return data;
        }
        else {
            var ev = jQuery.Event("valueChanging", { Controller: ins, OldValue: data, NewValue: value });
            this.Dom.trigger(ev);
            if (ev.isDefaultPrevented()) {
                return ins;
            }
            ev = jQuery.Event("valueChanged", { Controller: ins, OldValue: data, NewValue: value });
            data = value;

            if (ins.$model) {
                ins.$model.$data = data;
            }

            this.Dom.trigger(ev);
            ev = null;
            return ins;
        }
    };
    this.option = function (name, value) {
        /// <summary>
        /// 获取或设置某个选项的值
        /// </summary>
        /// <param name="name" type="string">选项名</param>
        /// <param name="value" type="object">选项值</param>
        if (!name) {
            return opt;
        }
        else if (value == null || value == undefined) {
            return opt[name];
        }
        else {
            opt[name] = value;
            return ins;
        }
    };
    this.dispose = function () {
        if (this.State && this.State.disposed == true) {
            return null;
        };
        this.State ? this.State.disposed = true : this.State = {};
        var ev = $.Event("disposed", { Controller: ins });
        if (this.Dom) {
            this.Dom.trigger(ev);
            this.Dom.Controller = null;
            this.Dom.remove();
        }

        data = null;
        ins = null;
        ev = null;
        opt = null;
        this.Dom = null;
        this.State = null;
        delete this.Dom;
        return this;
    };
    this.editble = false;

    var onDomClick = function (ev) {
        if (!ins.State.enabled || ins.State.enabled == false) {
            if (ev && ev.stopPropagation) {
                ev.stopPropagation();
            }
            return false;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCclick", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };
    var onDomBlur = function (ev) {
        if (ins.State.enabled == false) {
            return ins;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCblur", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };
    var onDomFocus = function (ev) {
        if (ins.State.enabled == false) {
            return ins;
        }
        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        }
        var nev = $.Event("LCfocus", { Controller: ins });
        ins.Dom.trigger(nev);
        return ins;
    };

    this.Dom.on("click", onDomClick);  //防止冲突，将Dom的Clic转换为自定义的LCclick事件
    this.Dom.on("blur", onDomBlur);
    this.Dom.on("focus", onDomFocus);
    this.Dom.data("Controller", ins);
    return ins;
};

LController.prototype = {
    "update": function () {
        if (this.State.disposed == false) {
            var ev = jQuery.Event("update", { Controller: this });
            this.Dom.trigger(ev);
        }
        return this;
    },
    "addClass": function (cssClass) {
        this.Dom.addClass(cssClass);
        return this;
    },
    "attr": function (name, value) {
        return this.Dom.attr(name, value);
    },
    "ID": function (newId) {
        return this.Dom.ID(newId);
    },
    "show": function () {
        if ((this.State && this.State.visible) || this.State.enabled == false) {
            return this;
        }

        this.State.visible = true;
        var ev = jQuery.Event("shown", { Controller: this });
        if (this.option("ShowWay")) {
            this.option("ShowWay").call(this, this.Dom);
        }
        else {
            this.Dom.fadeIn();
        }
        this.Dom.trigger(ev);
        return this;
    },
    "hide": function () {
        if (!this.State || !this.State.visible) {
            return this;
        }
        this.State.visible = false;
        var ev = jQuery.Event("hiden", { Controller: this });
        if (this.option("HideWay")) {
            this.option("HideWay").call(this, this.Dom);
        }
        else {
            this.Dom.fadeOut();
        }
        this.Dom.trigger(ev);
        return this;
    },
    "focus": function () {
        var ev = jQuery.Event("LCfocus", { Controller: this });
        this.Dom.trigger(ev);
        return this;
    },
    "disable": function () {
        this.State.enabled = false;
        var ev = jQuery.Event("disabled", { Controller: this });
        this.Dom.trigger(ev).addClass("disabled").attr("disabled", "disabled");
        this.update();
        return this;
    },
    "enable": function () {
        this.State.enabled = true;
        var ev = jQuery.Event("enabled", { Controller: this });
        this.Dom.trigger(ev).removeClass("disabled");
        this.update();
        return this;
    }
};

//#region 文件上传
LiberUI.Uploader = function ($elm) {
    var ins = this;
    LController.call(this, $elm);

    this.option("FileAPI", "/File/Up")
        .option("Open", "user")  //开放模式 open-无控制,user-限已登录用户,biz-需授权
        .option("Overide", false)  //是否覆盖相同的文件
        .option("UploadNow", true)  //实时上传，or等待用户点击提交
        .option("Multiple", false)  //允许多选
        .option("Thumbnail", true)  //对于图片，是否加载缩略图
        .option("FileType", "")  //允许的文件类型
        .option("MaxSize", 100000000)  //最大文件长度100m
        .option("BlockSize", 40960)  //分块大小，默认40k
        .option("Rename", "")  //重命名
        .option("RandomRename", false)  //开启随机重命名
        .option("MinSize", 1024);   //最小文件长度1k
    ins.vl([]);
    var _input = null;
    _input = $("<input type=file>").hide().appendTo("body");

    var onClick = function (ev) {
        _input.val("");
        //_input.click();
        _input.trigger("click");
    };

    //TODO:将筛选直接设为input的accept属性

    var onUpdate = function (ev) {
        if (ins.option("Multiple") == true) {
            $(_input).attr("Multiple", "multiple");
        }
        else {
            $(_input).removeAttr("Multiple");
        }
        if (ins.option("FileType") == "image/*") {
            ins.option("FileType", ".jpg,.jpeg,.png,.bmp");
        }

        $(_input).attr("accept", ins.option("FileType").toLowerCase());
    };

    var onSlcted = function (ev) {
        if (ins.State.enabled == false) {
            return;
        }
        if (this.files.length == 0) {
            return;
        }
        for (var i = 0; i < this.files.length; i++) {
            var f = this.files[i];
            var fileItems = ins.vl();
            /*检测文件类型限制*/
            var fType = f.name.substring(f.name.lastIndexOf('.'), f.name.length).toLowerCase();

            if (ins.option("FileType").length > 0 && ins.option("FileType").indexOf(fType) == -1) {
                err("错误", "文件类型不符合上传条件。允许的文件类型包括：" + ins.option("FileType"));
                return;
            }

            /*检测文件大小限制*/
            if (ins.option("MaxSize") && ins.option("MaxSize") < f.size) {
                err("错误", "文件大小超过最大限制");
                return;
            };

            var itm = {
                name: ins.option("Rename") == "" ? f.name : ins.option("Rename") + fType,
                uploader: ins,
                obj: f,
                process: 0,
                total: f.size,
                completed: -1,
                thumbnail: "",
                token: "",
                err: "",
                IsAborted: false,
                Change: LiberUI.UploaderBase.onChange
            };
            if (ins.option("RandomRename") == true) {
                itm.name = ((Math.random() / 2 + f.size / 2).toString() + new Date().getMilliseconds().toString()).MD5() + fType;
            }

            itm.name = itm.name.replace(/%/g, "").replace(/&/g, "");
            if (f.size > ins.option("MaxSize")) {
                itm.Result = { IsPositive: false, ErrorSrc: "Uploader", ErrorCode: "TooLarge" };
                itm.Change("uploadFail");
                return;
            };

            if (ins.option("Multiple") == false) {
                /*如果是单选模式*/
                fileItems.length > 0 ? fileItems[0] = itm : fileItems.push(itm);
            }
            else {
                fileItems.push(itm);
            }

            itm.Change("itemSlcted");
            if (f.type.match("image") && ins.option("Thumbnail") == true) {
                //开启了图片预览
                if (window.File && window.FileReader && window.FileList && window.Blob) {
                    var reader = new FileReader();
                    reader.onload = LiberUI.UploaderBase.onImageThumbnailLoad;
                    reader.item = itm;
                    reader.readAsDataURL(f);
                }
                else {
                    //如果不支持，另外处理
                    log("浏览器不支持Html5文件API");
                    break;
                }
            }

            if (ins.option("UploadNow") == true) {
                if (f.size > 8388608) {
                    //大于8m的，则根据token校验是否存在
                    LiberUI.UploaderBase.checkInfo(itm);
                }
                else {
                    LiberUI.UploaderBase.uploadItemH5(itm);
                }
            }

        }
    };

    var onItemChange = function (ev) {
        switch (ev.Status) {
            case "fileReading":
                //文件读取中
                break;
            case "fileReadEnd":
                //文件读取完毕
                break;
            case "checkInfoEnd":
                //检查文件信息完毕
                if (!ev.Item.Result && (ins.option("UploadNow") == true || ev.Item.uploadNow == true)) {
                    ev.Item.Change("uploadBegin");
                    LiberUI.UploaderBase.uploadItemH5(ev.Item);
                }
                break;
            case "uploadProcessing":
                //文件上传过程中，显示上传进度
                break;
            case "uploadEnd":
                //上传结束
                console.log(ev);

                break;
            case "uploadFail":
                //上传失败
                break;
            case "imageLoaded":
                //图像预览加载完毕
                if (ev.Item.thumbnail && ins.Dom.is("img")) {
                    ins.Dom.attr("src", ev.Item.thumbnail);
                }
                break;
        }
    };

    this.Upload = function (_itmIndex) {
        var i = parseInt(_itmIndex);
        if (!isNaN(i)) {
            //大于8m的，先检测token再上传
            var itm = ins.vl()[i];
            if (itm.obj.size > 8388608) {
                itm.uploadNow = true;
                LiberUI.UploaderBase.checkInfo(itm);
            }
            else {
                LiberUI.UploaderBase.uploadItemH5(itm);
            }
        }
        else {
            var fileItems = ins.vl();
            for (var i = 0; i < fileItems.length; i++) {
                if (fileItems[i].obj.size > 8388608) {
                    fileItems[i].uploadNow = true;
                    LiberUI.UploaderBase.checkInfo(fileItems[i]);
                }
                else {
                    fileItems[i].Change("uploadBegin");
                    LiberUI.UploaderBase.uploadItemH5(fileItems[i]);
                }

            }
        }
        return this;
    };

    this.Abort = function (_itemIndex) {
        if (parseInt(_itemIndex)) {
            var i = ins.vl()[_itemIndex];
            i.IsAborted = true;
            if (i.handler) {
                i.handler.abort();
                i.handler = null;
            }
        }
        else {
            var fileItems = ins.vl();
            for (var i = 0; i < fileItems.length; i++) {
                fileItems[i].IsAborted = true;
                if (fileItems[i].handler) {
                    fileItems[i].handler.abort();
                    fileItems[i].handler = null;
                }
            }
        }
        return this;
    };

    this.Clear = function (_itemIndex) {
        if (parseInt(_itemIndex)) {
            ins.vl(ins.vl().splice(_itemIndex));
        }
        else {
            ins.vl([]);
        }
        return this;
    };

    _input.on("change", onSlcted);

    this.on("update", onUpdate);
    this.on("click", onClick);
    this.on("change", onItemChange);
    this.on("disabled", function () { _input.attr("disabled", true); });
    this.on("enabled", function () { _input.attr("disabled", false); });
    this.on("valueChanging", function (e) {
        if (e.NewValue == null || e.NewValue.length == 0) {
            var fileItems = ins.vl();
            for (var i = 0; i < fileItems.length; i++) {
                if (fileItems[i].handler && fileItems[i].handler.dispose) {
                    fileItems[i].handler.dispose();
                    fileItems[i].uploader = null;
                    fileItems[i] = null;
                }
            }
        }
    });

    this.constructor = LiberUI.Uploader;
}
LiberUI.Uploader.prototype = LController.prototype;
LiberUI.UploaderBase = {
    Filter: function (_types) {

    },
    onChange: function (ev) {
        //发出当前上传过程事件
        var nev = jQuery.Event("change", { Controller: this.uploader, Item: this, Status: ev });
        this.uploader.Dom.trigger(nev);
    },
    onImageThumbnailLoad: function (ev) {
        this.item.thumbnail = this.result;
        this.onload = LiberUI.UploaderBase.onItemLoad;
        this.item.Change("imageLoaded");
        this.item = null;
    },
    onItemLoad: function (ev) {
        /// <summary>
        /// 读取成功完成
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoad");
        return this;
    },
    onItemLoadEnd: function (ev) {
        /// <summary>
        /// 读取结束（可能失败，也可能成功）
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoadEnd");
        return this;
    },
    onItemLoading: function (ev) {
        /// <summary>
        /// 读取过程中
        /// </summary>
        /// <param name="ev" type="type"></param>
        this._item.Change("fileLoading");
        return this;
    },
    checkInfo: function (itm) {
        var f = itm.obj;
        var md5Token = "";
        var url = itm.uploader.option("FileAPI") + "?mode=getInfo&fileName=" + encodeURIComponent(itm.name);

        //计算md5token作为唯一标识
        try {
            var tmpReader = new FileReader();
            tmpReader.readAsArrayBuffer(f);
            itm.Change("fileReading");
            tmpReader.item = itm;
            tmpReader.onload = function (e) {
                if (!this.item.token) {
                    var bufer = this.result;
                    var head = new Uint16Array(bufer, 0, 10240);
                    var mid = new Uint16Array(bufer, parseInt(bufer.byteLength / 8) * 2, 10240);
                    var tail = new Uint16Array(bufer, parseInt(bufer.byteLength / 4) * 2 - 10240, 10240);

                    md5Token = (String.fromCharCode.apply(null, head) + String.fromCharCode.apply(null, mid) + String.fromCharCode.apply(null, tail) + bufer.byteLength.toString()).MD5();

                    this.item.token = md5Token;
                    this.item.dataObj = bufer;
                    url += "&token=" + md5Token;
                    this.item.Change("checkInfo");
                    var checker = new XMLHttpRequest();
                    checker.open("get", url);
                    checker.onreadystatechange = LiberUI.UploaderBase.onCheckInfoEnd;
                    checker.item = this.item;
                    checker.send();
                }
            };
        }
        catch (ex) {
            md5Token = "";
            url += "&token=" + md5Token;
            itm.Change("checkInfo");
            var checker = new XMLHttpRequest();
            checker.open("get", url);
            checker.onreadystatechange = LiberUI.UploaderBase.onCheckInfoEnd;
            checker.item = itm;
            checker.send();
        }
    },
    onCheckInfoEnd: function (ev) {
        /// <summary>
        /// 检查服务端是否存在指定文件或片段
        /// </summary>
        /// <param name="ev" type="type"></param>
        if (this.readyState == 4 && this.status == 200 && this.response) {
            this.onreadystatechange = null;
            var rtn = this.response.toJSON();
            if (rtn.IsPositive) {
                if (rtn.Data.completed < rtn.Data.length) {
                    //获取到已经上传的进度，准备从已完成的部分开始继续上传
                    this.item.completed = rtn.Data.completed;
                }
                else {
                    //已经传完了
                    this.item.Result = rtn.Data;
                    this.item.completed = rtn.Data.completed;
                    this.item.Change("uploadEnd");
                }
            }
            else {
                //没有查到进度，从头开始传
                this.item.completed = 0;
            }
            this.item.Change("checkInfoEnd");
        }
    },
    uploadItemH5: function (itm) {
        if (itm.handler) {
            itm.Change("uploadEnd");
            return;
        };
        if (itm.total <= itm.completed) {
            //已经传完了
            itm.Change("uploadEnd");
            return;
        };
        if (itm.obj.size > 8388608 || itm.completed > 0) {
            //大于8m的，分段读取，分段上传
            var url = itm.uploader.option("FileAPI") + "?mode=append&fileName=" + encodeURIComponent(itm.name);
            url += "&token=" + itm.token;
            url += "&open=" + (itm.uploader ? itm.uploader.option("Open") : "user");
            url += "&overide=" + (itm.uploader ? itm.uploader.option("Overide") : false);
            itm.handler = new XMLHttpRequest();
            itm.handler.withCredentials = true;
            itm.handler.item = itm;
            itm.handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;  //上传完成继续下一次追加上传
            var blockSize = parseInt(itm.uploader.option("BlockSize"));
            var fd = new FormData();
            var ln = Math.min(blockSize, itm.total - itm.completed);  //分块上传
            var data = itm.obj.slice(itm.completed, itm.completed + ln);  //自上次完成位置读取分段数据

            fd.append("file", data, itm.name);
            fd.append("token", itm.token);
            itm.handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
            //itm.handler.setRequestHeader("X-Liber-UTkn", $.Cookie("uTicket"));
            itm.handler.send(fd);
        }
        else if (itm.obj.size > 512000) {
            //大于500k的，优先采用流式上传
            itm.token = "";
            if (window.FileReader) {
                //H5环境，使用FileReader上传
                var reader = new FileReader();
                reader.item = itm;
                reader.onload = LiberUI.UploaderBase.fileReadEnd;
                reader.readAsArrayBuffer(itm.obj);
            }
            else {
                //否则直接以文件方式上传
                var url = itm.uploader.option("FileAPI") + "?mode=upload&fileName=" + encodeURIComponent(itm.name);
                url += "&open=" + (itm.uploader ? itm.uploader.option("Open") : "user");
                url += "&overide=" + (itm.uploader ? itm.uploader.option("Overide") : false);
                itm.handler = new XMLHttpRequest();
                itm.handler.item = itm;
                itm.handler.withCredentials = true;
                itm.handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;
                var fd = new FormData();
                fd.append("file", itm.obj, itm.name);
                itm.handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
                //itm.handler.setRequestHeader("X-Liber-UTkn", $.Cookie("uTicket"));
                itm.handler.send(fd);
            }
        }
        else {
            //否则直接以文件方式上传
            var url = itm.uploader.option("FileAPI") + "?mode=upload&fileName=" + encodeURIComponent(itm.name);
            //url += "&token=" + itm.token;
            url += "&open=" + (itm.uploader ? itm.uploader.option("Open") : "user");
            url += "&overide=" + (itm.uploader ? itm.uploader.option("Overide") : false);
            itm.handler = new XMLHttpRequest();
            itm.handler.withCredentials = true;
            itm.handler.item = itm;

            itm.handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;

            var fd = new FormData();
            fd.append("file", itm.obj, itm.name);
            itm.handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
            //itm.handler.setRequestHeader("X-Liber-UTkn", $.Cookie("uTicket"));
            itm.handler.send(fd);
        }
    },
    appendEnd: function (ev) {
        if (this.readyState == 4 && this.response.length > 0) {
            if (this.item.IsAborted) {
                itm.Change("uploadCanceled");
                return;
            }
            var rtn = this.response.toJSON();
            var itm = this.item;
            if (rtn.IsPositive) {
                itm.completed = rtn.Data.completed;
                if (itm.completed < this.item.total) {
                    itm.Change("uploadProcessing");
                    var url = itm.uploader.option("FileAPI") + "?mode=append&fileName=" + encodeURIComponent(itm.name);
                    url += "&token=" + itm.token;
                    url += "&open=" + (itm.uploader ? itm.uploader.option("Open") : "user");
                    url += "&overide=" + (itm.uploader ? itm.uploader.option("Overide") : false);
                    itm.handler = new XMLHttpRequest();
                    itm.handler.withCredentials = true;
                    itm.handler.onreadystatechange = LiberUI.UploaderBase.appendEnd;
                    itm.handler.item = itm;

                    var fd = new FormData();
                    var blockSize = parseInt(itm.uploader.option("BlockSize"));
                    var ln = Math.min(blockSize, itm.total - itm.completed);
                    var data = itm.obj.slice(itm.completed, itm.completed + ln);  //自上次完成位置读取分段数据

                    fd.append("file", data);
                    fd.append("token", itm.token);
                    itm.handler.open("post", url + "&start=" + itm.completed + "&total=" + itm.total);
                    itm.handler.send(fd);
                }
                else {
                    itm.handler = null;
                    itm.Result = rtn.Data;
                    itm.Change("uploadEnd");
                }
            }
            else {
                itm.Result = rtn;
                itm.Change("uploadFail");
            }
        }
    },
    fileReadEnd: function (ev) {
        var itm = this.item;
        if (!itm.handler) {
            var url = itm.uploader.option("FileAPI") + "?mode=upload&fileName=" + encodeURIComponent(itm.name);
            url += "&token=" + itm.token;
            url += "&open=" + (itm.uploader ? itm.uploader.option("Open") : "user");
            url += "&overide=" + (itm.uploader ? itm.uploader.option("Overide") : false);
            itm.handler = new XMLHttpRequest();
            itm.handler.withCredentials = true;
            itm.handler.item = itm;
            itm.handler.upload.item = itm;
            itm.handler.upload.onprogress = LiberUI.UploaderBase.fileUploading;
            itm.handler.onreadystatechange = LiberUI.UploaderBase.fileUploadEnd;
            itm.handler.open("post", url);
            //itm.handler.setRequestHeader("X-Liber-UTkn", $.Cookie("uTicket").md4());
            itm.handler.send(this.result);
            itm.Change("fileReadEnd");
        }

    },
    fileUploading: function (ev) {
        var itm = this.item;
        itm.completed = ev.loaded;
        itm.Change("uploadProcessing");
    },
    fileUploadEnd: function (ev) {
        if (this.readyState == 4 && this.response.length > 0) {
            var rtn = this.response.toJSON();
            var itm = this.item;
            if (rtn.IsPositive) {
                itm.Result = rtn.Data;
                itm.Change("uploadEnd");
            }
            else {
                itm.Result = rtn;
                itm.Change("uploadFail");
            }
            this.item = null;
            this.upload.item = null;
        }
    }
}
//#endregion

//#region 提示框
LiberUI.Prompt = function ($elm) {
    var ins = this;
    var closer = null;
    //var mask = null;
    LController.call(this, $elm);

    this.option("Delay", 3);

    var onUpdate = function () {
        var dly = ins.option("Delay");
        if (!dly) {
            dly = 3;
        }
        closer = setTimeout(function () { ins.Dom.removeClass("prompt_active").addClass("prompt_dispose"); setTimeout(function () { ins.dispose(); }, 1000) }, (dly - 1) * 1000);
    };

    var onShow = function () {
        ins.Dom.appendTo("body");
        LayoutHelper.Layout2Wnd(ins.Dom, "AllCenter", null);
        ins.Dom.addClass("prompt_active");
    };

    var onDispose = function () {
        clearTimeout(closer);
        ins.Dom.remove();
    };

    this.on("shown", onShow);
    this.on("disposed", onDispose);
    this.on("update", onUpdate);
    this.constructor = LiberUI.Prompt;
}
LiberUI.Prompt.prototype = LController.prototype;
//#endregion

//#region 对话框
LiberUI.Dialoger = function ($elm) {
    /// <summary>
    /// 对话框基础组件
    /// </summary>
    /// <param name="$elm" type="type"></param>
    /// <returns type="LiberUI.Dialoger"></returns>
    var ins = this;
    var btns = [];
    var fnOnEsc = null;
    var msk = null;
    var phost = null;
    var bodyElm = null;
    var headElm = null;
    var bottomElm = null;
    LController.call(this, $elm);
    ins.Dom.appendTo("body").hide();
    ins.option("MainStyle", "Normal")  //基础样式，取决于对话框的用途性质（Warning危险性操作，Normal一般性操作，Info信息告知）
        .option("Mode", "Box")  //"Flat"为扁平化模式,"Box"为默认模式
        .option("Keybord", true)
        .option("Width",0)
        .option("Closeble", true);  //是否允许用户直接关闭对话框，并触发取消按钮的事件

    this.Dom.addClass("Dialoger");
    if (this.Dom.children().length == 0) {
        headElm = $("<div class='dlg_head'><h4 style='display:none'></h4><i class='dlg_closer'></i></div>").appendTo(ins.Dom);
        bodyElm = $("<div class='dlg_body'>").appendTo(ins.Dom);
        bottomElm = $("<div class='dlg_bottom'>").appendTo(ins.Dom).addClass("dlg_bottom");
    };

    var _onKbEnter = function (ev) {
        if (btns.length > 0 && btns[0].fn && ins.State.enabled == true) {
            var r = btns[0].fn(ins, bottomElm && bottomElm.children(".btnEnter").eq(0));
            ev.stopPropagation();
            if (r == true) {
                ins.hide();
            }
            else if (r == false) {

            }
            else {
                ins.hide();
            }
        };
    };
    var _onKbEsc = function (ev) {
        _closeDlg(ev);
    };
    var _update = function () {
        if (headElm) {
            if (ins.option("Mode") == "Flate") {
                ins.Dom.addClass("Flate");
            }
            else {
                ins.Dom.removeClass("Flate");
            }
            ins.Dom.addClass(ins.option("MainStyle"));

            bottomElm.children(".dlg_btn").remove();

            if (btns.length == 0) {
                bottomElm.hide();
                bodyElm.css("margin-bottom", '1rem');
            }
            else {
                bodyElm.css("margin-bottom", '4rem');
                for (var i = 0; i < btns.length; i++) {
                    var nb = $("<button class='dlg_btn'>").vl(btns[i].title).attr("btnIndex", i);
                    nb.appendTo(bottomElm);
                    nb.addClass(btns[i].class);
                }

            };

            if (!ins.option("Closeble")) {
                headElm.children(".dlg_closer").hide();
            }
            else {
                headElm.children(".dlg_closer").show();
            }
        }
    };
    var _onBtn = function (ev) {
        if (ins.State.enabled == false) {
            return;
        }
        var btn = $(this);
        if (!btn.hasClass("dlg_btn")) {
            btn = btn.parent(".dlg_btn");
            if (btn.length == 0) {
                return;
            }
        }
        var b = parseInt(btn.attr("btnIndex"));
        if (btns[b] && btns[b].fn) {
            var r = btns[b].fn(ins, bottomElm && bottomElm.children("button").eq(b));
            if (r == true) {
                ins.hide();
            }
            else if (r == false) {

            }
            else {
                ins.hide();
            }
        }
    };
    var _onWheel = function (ev) {
        if (ev) {
            ev.stopPropagation();
            return false;
        }
    };
    var _onShow = function () {
        bodyElm.css("width", 200);
        var outerW = bodyElm.outerWidth();
        if (ins.option("Width") > 0) {

            var w = ins.option("Width") < 100 ? document.body.clientWidth * ins.option("Width") / 100 : ins.option("Width");
            bodyElm.css("width", w);
            outerW = w;
        }
        else if (bodyElm && bodyElm.children().length > 0 && bodyElm[0].childNodes[0].clientWidth) {
            bodyElm.css("width", bodyElm[0].childNodes[0].clientWidth + 20);
            outerW = bodyElm[0].offsetWidth;
        }
        ins.Dom.width(outerW);

        msk = $('body').mask(ins.Dom).addClass("DialogMask");

        if (ins.option("Keybord") == true) {
            KeybordHelper.globalOn("enter", _onKbEnter);
            KeybordHelper.globalOn("esc", _onKbEsc);
        }

        ins.Dom.addClass("ani-flade-in-up");
        requestAnimationFrame(function () {
            var i = ins.Dom.find("input");
            if (i.length > 0) {
                i[0].focus();
            }
            else if (btns.length > 0) {
                bottomElm.find("button").eq(0).focus();
            }
            else {

            }
        });

        ins.off("hiden", _onHide).on("hiden", _onHide);
    };
    var _onHide = function () {
        if (phost !== null && phost.length > 0) {
            bodyElm.children().eq(0).appendTo(phost);
        }
        else {
            bodyElm.children().eq(0).hide().appendTo('body');
        }
        ins.Dom.hide().appendTo("body");
        ins.Dom.removeClass("ani-flade-in-up");
        KeybordHelper.globalOff("enter", _onKbEnter);
        KeybordHelper.globalOff("esc", _onKbEsc);
        msk.remove();
        msk = null;

        ins.off("shown", _onShow).on("shown", _onShow);
    };
    var _closeDlg = function (ev) {
        if (ins.option("Closeble") == false) {
            return;
        };

        if (fnOnEsc && ins.State.enabled == true) {
            fnOnEsc(ins, bottomElm && bottomElm.children(".btnEsc").eq(0));
            ev.stopPropagation();
        }
        else if (ins.State.enabled == false) {
            return;
        }
        else {
            ins.hide();
        };

        if (ev && ev.stopPropagation) {
            ev.stopPropagation();
        };
    };
    var _onDispose = function () {
        if (msk) {
            msk.remove();
            msk = null;
        };
        ins.off("shown", _onShow);
        ins.off("hiden", _onHide);
        ins.off("update", _update);
        ins.off("mousewheel", _onWheel);
        ins.off("dispose", _onDispose);
        if (headElm) {
            headElm.undelegate(".dlg_closer", "click", _closeDlg);
            bottomElm.undelegate(".dlg_btn", "click", _onBtn);
        };

        KeybordHelper.globalOff("enter", _onKbEnter);
        KeybordHelper.globalOff("esc", _onKbEsc);
        btns = [];
        fnOnEsc = null;
    };
    var _onDisable = function () {
        //TODO:对话框遮罩式禁用状态
    };
    var _onEnable = function () {
        //TODO:对话框取消禁用遮罩
    };

    this.Title = function (titl) {
        if (headElm) {
            if (titl && titl.length > 0) {
                headElm.children('h4').vl(titl.toString()).show();
            }
            else {
                headElm.hide();
            }
        }

        return this;
    };
    this.Content = function (cnt) {
        if (bodyElm) {
            if (ObjHelper.IsElement(cnt)) {
                bodyElm.vl('');
                phost = $(cnt).parentsUntil('body').eq(0);
                bodyElm.append(cnt);
            }
            else {
                bodyElm.vl(cnt);
            }
        }
        else {
            if (ObjHelper.IsElement(cnt)) {
                ins.Dom.vl('');
                phost = $(cnt).parentsUntil('body').eq(0);
                ins.Dom.append(cnt);
            }
            else {
                ins.Dom.vl(cnt);
            }
        }
        return this;
    };

    this.Resize = function (w, h) {
        if (bodyElm) {
            if (w) {
                bodyElm.css("width", w);
            }
            if (h) {
                bodyElm.css("height", h);
            }

            if (ins.State.visible) {
                ins.Dom.width(bodyElm.outerWidth());
                LayoutHelper.Layout2Parent(ins.Dom, "AllCenter");
            }
        }

        return ins;
    };

    this.BtnEnter = function (btnTitle, btnIcon, btnCallback, btnStyle) {
        if (!btnCallback) {
            btnCallback = _closeDlg;
        }
        btns.splice(0, 0, { title: btnTitle, icon: btnIcon, class: 'btnEnter ' + btnStyle, fn: btnCallback, index: 0 });
        return this;
    };
    this.BtnEsc = function (btnTitle, btnIcon, btnCallback, btnStyle) {
        if (!btnCallback) {
            //如果不指定，默认同关闭按钮处理方式
            btnCallback = _closeDlg;
        }
        else {
            //否则同时取代键盘Esc键功能
            fnOnEsc = btnCallback;
        }

        if (btns.length > 0) {
            btns.splice(1, 0, { title: btnTitle, icon: btnIcon, class: 'btnEsc ' + btnStyle, fn: btnCallback, index: 1 });
        }
        else {
            btns.splice(0, 0, { title: btnTitle, icon: btnIcon, class: 'btnEsc ' + btnStyle, fn: btnCallback, index: 0 });
        }
        return this;
    };
    this.BtnOther = function (btnTitle, btnIcon, btnCallback, btnStyle) {
        btns.splice(btns.length, 0, { title: btnTitle, icon: btnIcon, fn: btnCallback, class: btnStyle, index: btns.length });
        return this;
    };
    this.RemoveBtn = function (btnIndex) {
        btnIndex = parseInt(btnIndex);
        if (!isNaN(btnIndex) && btnIndex < btns.length) {
            btns.splice(btnIndex, 1);
        }
        else {
            btns = [];
        }
        return this;
    };
    this.Close = function (delay) {
        if (!delay) {
            ins.dispose();
        }
        else {
            setTimeout(function () { ins.dispose(); }, delay * 1000);
        }
    };

    this.on("shown", _onShow);
    this.on("hiden", _onHide);
    this.on("update", _update);

    bodyElm && bodyElm[0].addEventListener("mousewheel", _onWheel, { passive: true });
    this.on("disposed", _onDispose);
    this.on("disabled", _onDisable);
    this.on("enabled", _onEnable);
    if (this.option("Closeble") == true) {
        headElm && headElm.on("click", ".dlg_closer", _closeDlg);
    };

    bottomElm && bottomElm.on("click", ".dlg_btn", _onBtn);
    ins.constructor = LiberUI.Dialoger;
    return ins;
};
LiberUI.Dialoger.prototype = LController.prototype;
//#endregion

//#region 自动动态弹出面板
LiberUI.PopPanel = function ($elm) {
    var ins = this;
    var popFor = null;
    var mchecker = null;
    var flag = 0;
    var items = null;
    var slcted = -1;
    var _keyEnterHandler = null;

    LController.call(this, $elm);
    ins.Dom.ID();
    this.option("AutoPopout", true)
        .option("AutoHide", true)
        .option("Position", "down-left") /*位置，默认左下，可选right-up,right-down*/
        .option("Offset", { top: 0, left: 0 })
        .option("AutoWidth", true)
        .option("Exclusive", true)  /*独占模式，会强制关闭其他PopFor*/
        .option("ShowWay", PopPaneBase.ShowWay)
        .option("HideWay", PopPaneBase.HideWay);
    ins.Dom.hide();
    var _checkMouseElm = function (tDom) {
        if (!ins.popFor) {
            ins.hide();
            return;
        }
        clearTimeout(mchecker);
        if (tDom) {
            mchecker = setTimeout(_checkMouseElm, 500);
            return;
        }

        var elm = LiberUI.TryGetHotElement();

        if (elm && (elm[0] == ins.Dom[0] || elm.offsetParent()[0] == ins.Dom[0] || elm.parents('#' + ins.Dom.ID()).length > 0 || elm[0] == ins.popFor[0] || elm.offsetParent()[0] == ins.popFor[0] || elm.parents('#' + ins.popFor.ID()).length > 0)) {
            flag = 0;
            mchecker = setTimeout(_checkMouseElm, 200);
        }
        else if (flag > 1 || !ins.State.visible) {
            ins.hide();
            window.clearTimeout(mchecker);
            mchecker = null;
            flag = 0;
        }
        else {
            /*如果检测到鼠标移动到其他区域，延迟再检查2次来确定是否隐藏*/
            flag += 1;
            mchecker = setTimeout(_checkMouseElm, 200);
        }
    };
    var onShow = function (ev) {
        if (ins.State.enabled == false) {
            return;
        }
        if (ins.option("Exclusive") == true && PopPaneBase.Actived && PopPaneBase.Actived.Dom.ID() !== ins.Dom.ID()) {
            PopPaneBase.Actived.hide();
        };
        PopPaneBase.Actived = ins;

        if (ins.popFor && ins.option("AutoHide") == true) {
            ins.popFor.off("blur", blurView)
                .off('mouseleave', leaveView);
            ins.popFor.on("blur", blurView)
                .on("mouseleave", leaveView);

            ins.Dom.off("mouseleave", leaveElm);
            ins.Dom.off("scroll", scrollOnElm);
            ins.Dom.on("mouseleave", leaveElm);
            ins.Dom.on("scroll", scrollOnElm);
        }

        if (ins._keyEnterHandler && ins._keyEnterHandler instanceof Function) {
            KeybordHelper.globalOn("up", onKeyUp);
            KeybordHelper.globalOn("down", onKeyDown);
            KeybordHelper.globalOn("enter", onKeyEnter);
        };

        ins.off("hiden", onHide).on("hiden", onHide);
        ins.option("ShowWay").call(ins, ins.Dom);
    };
    var onHide = function (ev) {
        if (ins.popFor && ins.option("AutoPopout") == true) {
            ins.popFor.off("mouseenter", showView)
                .off("click", showView)
                .off("focus", showView);

            ins.popFor.on("mouseenter", showView)
                .on("click", showView)
                .on("focus", showView);
        }
        if (ins._keyEnterHandler && ins._keyEnterHandler instanceof Function) {
            KeybordHelper.globalOff("up", onKeyUp);
            KeybordHelper.globalOff("down", onKeyDown);
            KeybordHelper.globalOff("enter", onKeyEnter);
        }

        ins.off("shown", onShow)
            .on("shown", onShow);
    };

    var onKeyUp = function (ev) {
        if (ins.State.visible) {
            ev.preventDefault();
            ev.stopPropagation();
            ev.stopImmediatePropagation();
            if (!ins.items) {
                ins.items = ins.Dom.children();
                ins.slcted = ins.items - 1;
            }
            else {
                $(ins.items[ins.slcted]).removeClass("slcted");
                ins.slcted -= 1;
                if (ins.slcted < 0) {
                    ins.slcted = 0;
                }
            }
            $(ins.items[ins.slcted]).addClass("slcted");
        }
    };

    var onKeyDown = function (ev) {
        if (ins.State.visible) {
            ev.preventDefault();
            ev.stopPropagation();
            ev.stopImmediatePropagation();
            if (!ins.items) {
                ins.items = ins.Dom.children();
                ins.slcted = 0;
            }
            else {
                $(ins.items[ins.slcted]).removeClass("slcted");
                ins.slcted += 1;
                if (ins.slcted >= ins.items.length) {
                    ins.slcted = ins.items.length - 1;
                }
            }
            $(ins.items[ins.slcted]).addClass("slcted");
        }
    };

    var onKeyEnter = function (ev) {
        if (ins.State.visible && ins.slcted != -1) {
            ev.preventDefault();
            ev.stopPropagation();
            ev.stopImmediatePropagation();
            ins._keyEnterHandler && ins._keyEnterHandler.call(ins.items[ins.slcted]);
            ins.hide();
        }
    };

    var showView = function (ev) {
        ev && ev.preventDefault();
        ev && ev.stopPropagation();
        ev && ev.stopImmediatePropagation();
        ins.show();
    };

    var blurView = function (ev) {
        _checkMouseElm();
    };
    var leaveElm = function (ev) {
        _checkMouseElm();
    };
    var leaveView = function (ev) {
        _checkMouseElm();
    };

    var scrollOnElm = function (ev) {
        ev.stopPropagation();
        ev.stopImmediatePropagation();
    };
    var _onDisable = function () {
        ins.popFor && ins.popFor.addClass("disabled");
    };
    var _onEnable = function () {
        ins.popFor && ins.popFor.removeClass("disabled");
    };
    this.PopFor = function ($view) {
        $view = $($view);

        if (ObjHelper.IsElement($view)) {
            if ($view.length > 0) {
                $view = $view.eq(0);
            }
            else {
                ins.popFor = null;
                return ins;
            }

            if (ins.popFor && ins.popFor == $view) {
                return ins;
            };

            ins.popFor = $view;
            if (this.option("AutoPopout") == true) {
                ins.popFor.on("mouseenter", showView)
                    .on("click", showView)
                    .on("focus", showView);
            }
            var style = {
                disable: 'none',
                position: 'absolute',
                zIndex: 100
            }
            ins.Dom.css(style);
            return ins;
        }
        else {
            return ins.popFor;
        };
    };
    this.Keybord = function (fnCallback) {
        /// <summary>
        /// 启用键盘操作
        /// </summary>
        /// <param name="fnCallback" type="type">提供一个回调在用户使用键盘按下Enter键后触发</param>
        ins._keyEnterHandler = fnCallback;
        return this;
    };

    this.on("disabled", _onDisable);
    this.on("enabled", _onEnable);
    this.on("hiden", onHide);
    this.on("shown", onShow);

    ins.constructor = LiberUI.PopPanel;
    return ins;
};
LiberUI.PopPanel.prototype = LController.prototype;
var PopPaneBase = {
    'ShowWay': function ($elm) {
        var v = this.PopFor();
        if (!v) {
            return;
        }
        var p = this.option("Position") || 'down-left';
        var of = this.option("Offset") || { top: -1 };
        v.addClass("active");
        $elm.appendTo("body").show();
        if (this.option("AutoWidth") == true) {
            $elm.css("width", v.outerWidth());
        };

        $elm.css({ height: 'auto', visibility: 'visible' }).removeClass("ani-flade-out-up").addClass("ani-flade-in-up");
        LayoutHelper.PosToBody(v, $elm, p, of);
    },
    'HideWay': function ($elm) {
        var v = this.PopFor();
        if (!v) {
            return;
        }
        $elm.removeClass("ani-flade-in-up").addClass('ani-flade-out-up');
        v.removeClass("active");
    },
    'Actived': null
}
//#endregion

//#region 输入组校验器
LiberUI.InputChecker = function ($elm) {
    var ins = this;
    var regEmail = new RegExp(/^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/);
    var regMphone = new RegExp(/^1[0-9]{10}$/);
    var errTip = $("<span class='err'>");
    LController.call(this, $elm);
    ins.Dom.ID();
    ins.option("OnError", null);
    ins.option("ErrTip", "bottom");
    var reset = function (elm) {
        if (elm.hasClass("error")) {
            elm.removeClass("error");
            elm.siblings("span.err").remove();
        };
    };

    var setErr = function (elm, errType, errInfo) {
        if (elm.hasClass("error")) {
            return;
        }
        elm.addClass("error");
        if (ObjHelper.IsFunc(ins.option("OnError"))) {
            ins.option["OnError"].call(elm, errType, errInfo);
        }
        else {
            var tip = errTip.clone();
            if (ins.option("ErrTip") == "bottom") {
                tip.addClass("input-check-bottom");
            }
            else {
                tip.addClass("input-check");
            }
            tip.text(errInfo);
            tip.insertAfter(elm);
        }
    };

    var onChecking = function (e, ruls) {
        //清除上次的检查结果
        var elm = $(e);
        reset(elm);
        if (!ins.State.enabled) {
            return true;
        }
        var rs = elm.data();
        var v = elm.vl();
        if (rs["required"] && (!ruls || ruls.indexOf("required") > -1) && ObjHelper.IsEmpty(v)) {
            setErr(elm, "required", rs["required"]);
            return false;
        }
        if (rs["email"] && (!ruls || ruls.indexOf("email") > -1) && v.toString().length > 0 && !regEmail.test(v)) {
            setErr(elm, "email", rs["email"]);
            return false;
        }
        if (rs["mphone"] && (!ruls || ruls.indexOf("mphone") > -1) && v.toString().length > 0 && !regMphone.test(v)) {
            setErr(elm, "mphone", rs["mphone"]);
            return false;
        }
        if (rs["maxLength"] && (!ruls || ruls.indexOf("max-length") > -1) && v.toString().length > 0 && v.toString().length > rs["maxLength"]) {
            setErr(elm, "max-length", "输入内容长度不能超过" + rs["maxLength"] + "字符");
            return false;
        }
        if (rs["minLength"] && (!ruls || ruls.indexOf("min-length") > -1) && v.toString().length < rs["minLength"]) {
            setErr(elm, "min-length", "输入内容长度不能少于" + rs["minLength"] + "字符");
            return false;
        }
        return true;
    };

    this.CheckAll = function (ruls) {
        if (!ins.State.enabled) {
            return true;
        }
        var inputs = this.Dom.find("input");
        var r = true;
        inputs.each(function (i) {
            var currentR = onChecking($(this), ruls);
            r = r && currentR;
        });
        return r;
    };

    this.Dom.delegate("input", "blur", null, function () {
        var _this = this;
        /*延迟执行校验方法，解决失焦无法关闭弹窗，
         *避免插入dom元素导致弹窗大小变化，无法点中弹窗按钮
         */
        setTimeout(function () {
            onChecking($(_this));
        }, 200);
    });
    this.Dom.delegate("input", "keyup", null, function () { reset($(this)); });
    this.constructor = LiberUI.InputChecker;
};
LiberUI.InputChecker.prototype = LController.prototype;
//#endgion

//#region 鼠标跟随提示
LiberUI.ToolsTip = function () {
    var ins = this;
    var defTip = $("<div id='Tip-Box'>").insertAfter("body");
    var cusTip = $("<div id='Tip-Wraper'>").insertAfter("body");
    var tip = defTip;
    var tipFor = null;
    var tipHeigth = 0;
    var pos = null;
    var status = 0;
    LController.call(this, null);

    var updateRaw = function (e) {
        if (tipFor) {
            if (!e) {
                e = { pageY: tipHeight, pageX: 0 };
            }

            tip.css({ top: e.pageY - tipHeigth, left: e.pageX + 20 });
        }
        else {
            tip.css({ height: 0, minHeight: 0, padding: 0 });
        }
    };

    this.Cnt = function (str) {
        if (!str || str.length == 0) {
            this.Hide();
        }
        else if (str.indexOf('#') == 0) {
            cusTip[0].innerHTML = '';
            cusTip.append($(str));
            defTip.css({ height: 0, minHeight: 0, padding: 0 });
            tip = cusTip;
        }
        else {
            defTip.text(str);
            cusTip.css({ height: 0, minHeight: 0, padding: 0 });
            defTip.css({ height: 'auto', minHeight: '2rem', padding: '10px' });
            tip = defTip;
        };
        tipHeigth = tip[0].clientHeight + 10;
        return ins;
    };

    this.TipFor = function (toElm) {
        var tid = $(toElm).ID();
        if (tipFor !== null && tid == tipFor.ID()) {
            return ins;
        }
        else {
            status = 1;
            tipFor = $(toElm);
            pos = tipFor.offset();
        }
        return ins;
    };

    this.Hide = function (checked) {
        if (checked || status == 0) {
            tipFor = null;
            status = 0;
            updateRaw();
        }
        else {
            setTimeout(ins.Hide, 100, true);
        }
    };

    this.Update = function (e) {
        window.requestAnimationFrame(function () {
            updateRaw(e);
        });
        return ins;
    };

    ins.constructor = LiberUI.ToolsTip;
    return ins;
}
LiberUI.ToolsTip.prototype = LController.prototype;
//#endregion

//#region 可恢复到初始状态的对象
FixObj = function (jsonObj) {
    let _origin = JSON.clone(jsonObj || {});
    let _self = this;
    JSON.merge(_self, jsonObj || {});
    this.Update = function (newValues) {
        if (!newValues) {
            return _origin;
        }

        JSON.merge(_origin, newValues);
        JSON.merge(_self, newValues);
        return _self;
    };

    this.ToJSON = function () {
        var tmp = JSON.merge({}, _self);
        delete tmp._origin;
        delete tmp.Update;
        delete tmp.ToJSON;

        return JSON.stringify(tmp);
    };
    return this;
}
//#endregion